package com.bear.newsset.util;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import androidx.annotation.AnimRes;
import androidx.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;

import com.bear.newsset.R;

import static com.bear.newsset.util.AnimUtil.SHOW_STATUS.AUTO;
import static com.bear.newsset.util.AnimUtil.SHOW_STATUS.AUTO_TO_INVISIBLE;
import static com.bear.newsset.util.AnimUtil.SHOW_STATUS.NONE;

/**
 * 组件动画工具类
 *
 * @see #loadAnim
 * @see #loadAnim(Context, int, View)
 */
public class AnimUtil {
    public enum SHOW_STATUS {
        NONE,                   //无状态
        AUTO,                   //自动。隐藏方式：GONE
        AUTO_TO_INVISIBLE,      //自动。隐藏方式：INVISIBLE
        VISIBLE,                //显示
        GONE,                   //隐藏模式
        INVISIBLE               //隐藏模式
    }

    /**
     * 加载动画
     * @param mContext  上下文
     * @param animRes   动画资源
     * @param v         需要动画的View
     * @param status    显示状态{@link SHOW_STATUS}
     * @param <V>       泛型继承{@link View}
     * @return          返回动画
     */
    public static <V extends View> Animation loadAnim(Context mContext, @AnimRes int animRes, V v,
                                                      @NonNull SHOW_STATUS status) {
        Animation anim = AnimationUtils.loadAnimation(mContext, animRes);
        //设置动画监听器
        anim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) { }
            @Override
            public void onAnimationEnd(Animation animation) {
                int show = View.VISIBLE;
                switch ( status ) {
                    case NONE:
                        return;
                    case AUTO: case GONE:
                        show = View.GONE;
                        break;
                    case AUTO_TO_INVISIBLE: case INVISIBLE:
                        show = View.INVISIBLE;
                        break;
                }
                //动画结束时自动隐藏/显示View
                if( AUTO.equals(status) || AUTO_TO_INVISIBLE.equals(status) ) {
                    show = v.getVisibility() == View.VISIBLE ? show : View.VISIBLE;
                }
                if( v.getVisibility() != show ) v.setVisibility( show );
            }
            @Override
            public void onAnimationRepeat(Animation animation) { }
        });
        //设置动画
        v.startAnimation( anim );
        return anim;
    }

    public static <V extends View> Animation loadAnim(Context mContext, @AnimRes int animRes, V v) {
        return loadAnim(mContext, animRes, v, NONE);
    }

    /**
     * 从底部到顶部的动画
     * @param mContext  上下文
     * @param v         需要动画的View
     * @param status    显示状态{@link SHOW_STATUS}
     * @param <V>       泛型继承{@link View}
     */
    public static <V extends View> Animation loadAnimForToTop(Context mContext, V v,
                                                              SHOW_STATUS status) {
        return loadAnim(mContext, R.anim.anim_bottom_in, v, status);
    }
    public static <V extends View> void loadAnimForToTop(Context mContext, V v) {
        loadAnimForToTop(mContext, v, NONE);
    }

    /**
     * 从顶部到底部的动画
     * @param mContext  上下文
     * @param v         需要动画的View
     * @param status    显示状态{@link SHOW_STATUS}
     * @param <V>       泛型继承{@link View}
     */
    public static <V extends View> Animation loadAnimForToBottom(Context mContext, V v,
                                                                 SHOW_STATUS status) {
        return loadAnim(mContext, R.anim.anim_top_in, v, status);
    }
    public static <V extends View> Animation loadAnimForToBottom(Context mContext, V v) {
        return loadAnimForToBottom(mContext, v, NONE);
    }

    /**
     * 从左边到底部的动画
     * @param mContext  上下文
     * @param v         需要动画的View
     * @param status    显示状态{@link SHOW_STATUS}
     * @param <V>       泛型继承{@link View}
     */
    public static <V extends View> Animation loadAnimForToLeftIn(Context mContext, V v,
                                                                 SHOW_STATUS status) {
        return loadAnim(mContext, R.anim.anim_left_in, v, status);
    }
    public static <V extends View> Animation loadAnimForToLeftIn(Context mContext, V v) {
        return loadAnimForToBottom(mContext, v, NONE);
    }

    /**
     * 从左边到底部的动画
     * @param mContext  上下文
     * @param v         需要动画的View
     * @param status    显示状态{@link SHOW_STATUS}
     * @param <V>       泛型继承{@link View}
     */
    public static <V extends View> Animation loadAnimForToLeftOut(Context mContext, V v,
                                                               SHOW_STATUS status) {
        return loadAnim(mContext, R.anim.anim_left_out, v, status);
    }
    public static <V extends View> Animation loadAnimForToLeftOut(Context mContext, V v) {
        return loadAnimForToBottom(mContext, v, NONE);
    }

    /**
     * 从右边到底部的动画
     * @param mContext  上下文
     * @param v         需要动画的View
     * @param status    显示状态{@link SHOW_STATUS}
     * @param <V>       泛型继承{@link View}
     */
    public static <V extends View> Animation loadAnimForToRight(Context mContext, V v,
                                                               SHOW_STATUS status) {
        return loadAnim(mContext, R.anim.anim_right_in, v, status);
    }
    public static <V extends View> Animation loadAnimForToRight(Context mContext, V v) {
        return loadAnimForToBottom(mContext, v, NONE);
    }


    /**
     * 属性动画
     * @param v             View
     * @param name          属性名
     * @param from          起始值
     * @param to            目标值
     * @param duration      动画时长
     * @param <V>           必须继承View
     * @return              当前的属性动画
     */
    public static <V extends View> ObjectAnimator startObjAnim(@NonNull V v, @NonNull String name,
                                                            float from, float to, long duration) {
        ObjectAnimator animator = ObjectAnimator.ofFloat(v, name, from, to);
        animator.setDuration( duration );
        animator.setInterpolator(new DecelerateInterpolator());
        animator.start();

        return animator;
    }

    /**
     * 值动画
     * @param from          起始值
     * @param to            目标值
     * @param listener      监听器
     * @param duration      动画时长
     */
    public static void startValAnim(int from, int to, ValueAnimator.AnimatorUpdateListener listener,
                              long duration) {
        ValueAnimator animator = ValueAnimator.ofInt(from, to);
        animator.setDuration( duration );
        animator.setInterpolator(new DecelerateInterpolator());
        animator.addUpdateListener( listener );
        animator.start();
    }

    /**
     * X轴移动动画
     * @param v         View
     * @param moveX     目标X轴
     * @param <V>       必须继承View
     */
    public static <V extends View> void startMoveXAnim(@NonNull V v, float moveX) {
        startObjAnim(v, "x", v.getX(), moveX, 200);
    }

    /**
     * Y轴移动动画
     * @param v         View
     * @param moveY     目标y轴
     * @param <V>       必须继承View
     */
    public static <V extends View> void startMoveYAnim(@NonNull V v, float moveY) {
        startObjAnim(v, "y", v.getY(), moveY, 200);
    }

    /**
     * 阿尔法值动画
     * @param v         View
     * @param show      显示/隐藏
     * @param <V>       必须继承View
     */
    public static <V extends View> void startAlphaAnim(@NonNull V v, boolean show) {
        float from = show ? 0F : 1F;
        float to = show ? 1F : 0F;
        ObjectAnimator animator = startObjAnim(v, "alpha", from, to, 150);
        if( show ) {
            v.setVisibility( View.VISIBLE );
        }else {
            v.postDelayed(() -> v.setVisibility( View.INVISIBLE ), animator.getDuration());
        }
    }

    /**
     * 缩放动画
     * @param v     View
     * @param to    缩放值
     * @param <V>   必须继承View
     */
    public static <V extends View> void startZoomAnim(@NonNull V v, int to) {
        startValAnim(v.getWidth(), to, animation -> {
            ViewGroup.LayoutParams lp = v.getLayoutParams();
            int size = Integer.valueOf(animation.getAnimatedValue().toString());
            lp.width = size;
            lp.height = size;
            v.setLayoutParams( lp );
        }, 200);
    }
}
